package com.xyht.sca_s.student_manage_system.modules.meeting.util;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ExceptionCast;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.meeting.entity.*;
import com.xyht.sca_s.student_manage_system.modules.meeting.entity.resp.SmsMeetingRoomInfoResp;
import com.xyht.sca_s.student_manage_system.modules.meeting.mapper.*;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.AppTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.RangeTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.TipsTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.util.NewTipsUtil;
import com.xyht.sca_s.student_manage_system.modules.org.entity.SmsOrgStructure;
import com.xyht.sca_s.student_manage_system.modules.org.mapper.SmsOrgStructureMapper;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.meeting.constant.MeetingRoomAllowStatusConstant.MEETING_ALLOW_STATUS_PASS;
import static com.xyht.sca_s.student_manage_system.modules.meeting.constant.MeetingRoomAllowStatusConstant.MEETING_ALLOW_STATUS_WAIT;
import static com.xyht.sca_s.student_manage_system.modules.meeting.constant.MeetingRoomDetailAllowStatusConstant.MEETING_DETAIL_ALLOW_STATUS_WAIT;

/**
 * <p>
 * 会议室预定 工具类
 * </p>
 *
 * @author XYHT
 * @since 2023-08-03
 */
@Component
@Log4j2
public class AddMeetingUtil {
    @Autowired
    private SmsMeetingRoomPredetermineApplyMapper smsMeetingRoomPredetermineApplyMapper;
    @Autowired
    private SmsMeetingRoomInfoMapper smsMeetingRoomInfoMapper;
    @Autowired
    private SmsMeetingRoomProcessDetailMapper smsMeetingRoomProcessDetailMapper;
    @Autowired
    private NewTipsUtil newTipsUtil;
    @Autowired
    private SmsOrgStructureMapper smsOrgStructureMapper;
    @Autowired
    private SmsMeetingBuildingMapper smsMeetingBuildingMapper;
    @Autowired
    private SmsMeetingBuildingFloorMapper smsMeetingBuildingFloorMapper;

    /**
     * 添加会议室预约申请
     *
     * @param meetingRoomId 会议室id
     * @param name          会议主题
     * @param startDate     开始时间
     * @param endDate       结束时间
     * @param memberIdList  参与者idList
     * @param userId        申请人id
     * @return
     */
    public String addMeeting(String meetingRoomId, String name, Date startDate, Date endDate, List<String> memberIdList, String userId) {
        //校验会议室预约时间
        if (startDate.compareTo(endDate) > 0 || endDate.compareTo(TimeUtil.GetEndDate(startDate)) > 0 || startDate.compareTo(new Date()) < 0) {
            return null;
        }

        //校验会议室是否存在
        SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(meetingRoomId);
        if (isNullOrEmpty(meetingRoom)) {
            return null;
        }
        //校验会议室状态
        if (!meetingRoom.getIsUse()) {
            return null;
        }
        //校验容量
        if (memberIdList.size() > meetingRoom.getCapacity()) {
            return null;
        }
        //校验会议室预定时间
        if (meetingRoom.getIsBookTime()) {
            //校验开始时间和结束时间限制
            Date startTimeLimit = meetingRoom.getStartTimeLimit();
            startTimeLimit.setYear(startDate.getYear());
            startTimeLimit.setMonth(startDate.getMonth());
            startTimeLimit.setDate(startDate.getDate());
            Date endTimeLimit = meetingRoom.getEndTimeLimit();
            endTimeLimit.setYear(endTimeLimit.getYear());
            endTimeLimit.setMonth(endTimeLimit.getMonth());
            endTimeLimit.setDate(endTimeLimit.getDate());

            if (!((startDate.compareTo(startTimeLimit) > 0 && startDate.compareTo(endTimeLimit) < 0)
                    && (endDate.compareTo(startTimeLimit) > 0 && endDate.compareTo(endTimeLimit) < 0))) {
                return null;
            }
            //校验是否超出会议室单次可预订时长上限
            long applyStartDateTime = startDate.getTime();
            long applyEndDateTime = endDate.getTime();
            int minutes = (int) ((applyEndDateTime - applyStartDateTime) / (1000 * 60));
            if (minutes > meetingRoom.getSingleTimeLimit()) {
                return null;
            }
            //校验是否超出会议室最早可提前预定时间
            long nowTime = new Date().getTime();
            int hours = (int) ((applyStartDateTime - nowTime) / (1000 * 60 * 60));
            if (hours > meetingRoom.getEarliestBookTime()) {
                return null;
            }
        }

        //校验是否有申请 存在交集
        Integer count = smsMeetingRoomPredetermineApplyMapper.selectCount(new LambdaQueryWrapper<SmsMeetingRoomPredetermineApply>()
                .eq(SmsMeetingRoomPredetermineApply::getMeetingRoomId, meetingRoomId)
                .eq(SmsMeetingRoomPredetermineApply::getAllowStatus, MEETING_ALLOW_STATUS_PASS)
                .not(queryWrapper ->
                        queryWrapper.le(SmsMeetingRoomPredetermineApply::getEndTime, startDate)
                                .or()
                                .ge(SmsMeetingRoomPredetermineApply::getStartTime, endDate)));
        if (count > 0) {
            return null;
        }

        //创建预定申请表
        SmsMeetingRoomPredetermineApply predetermineApply = new SmsMeetingRoomPredetermineApply();
        predetermineApply.setUserId(userId);
        predetermineApply.setName(name);
        predetermineApply.setMeetingRoomId(meetingRoomId);
        predetermineApply.setAllowStatus(MEETING_ALLOW_STATUS_WAIT);
        predetermineApply.setStartTime(startDate);
        predetermineApply.setEndTime(endDate);
        predetermineApply.setMemberIdList(JSON.toJSONString(memberIdList));
        smsMeetingRoomPredetermineApplyMapper.insert(predetermineApply);

        //校验是否需要审批 同时 进行通知
        if (meetingRoom.getIsAllow()) {
            List<String> AllowUserIdList = JSON.parseArray(meetingRoom.getAllowUserIdList(), String.class);
            for (String allowUserId : AllowUserIdList) {
                SmsMeetingRoomProcessDetail addDetail = new SmsMeetingRoomProcessDetail();
                addDetail.setApplyId(predetermineApply.getId());
                addDetail.setIsSign(meetingRoom.getIsSign() ? 1 : 0);
                addDetail.setIsStamp(meetingRoom.getIsStamp() ? 1 : 0);
                addDetail.setUserId(allowUserId);
                addDetail.setAllowStatus(MEETING_DETAIL_ALLOW_STATUS_WAIT);
                smsMeetingRoomProcessDetailMapper.insert(addDetail);

                //消息通知
                List<String> rangeList = new ArrayList<>();
                rangeList.add(allowUserId);
                newTipsUtil.addNewTips(TipsTypeEnum.TIPS_TYPE_ENUM_ALLOW,
                        userId,
                        RangeTypeEnum.RANGE_TYPE_ENUM_PERSON,
                        rangeList,
                        AppTypeEnum.APP_TYPE_ENUM_MEETING_ROOM,
                        predetermineApply.getId(),
                        addDetail.getId());
            }
        } else {
            predetermineApply.setAllowStatus(MEETING_ALLOW_STATUS_PASS);
            predetermineApply.setApplyEndTime(new Date());
            smsMeetingRoomPredetermineApplyMapper.updateById(predetermineApply);

            //消息通知
            newTipsUtil.allowFinishTips(predetermineApply.getId(), userId, true);
        }

        return predetermineApply.getId();
    }

    /**
     * 修改会议室预约申请
     *
     * @param applyId       申请表id
     * @param meetingRoomId 会议室id
     * @param name          会议主题
     * @param startDate     开始时间
     * @param endDate       结束时间
     * @param memberIdList  参与者idList
     * @param userId        申请人id
     */
    public void updateMeeting(String applyId, String meetingRoomId, String name, Date startDate, Date endDate, List<String> memberIdList, String userId) {
        //校验申请表是否存在
        SmsMeetingRoomPredetermineApply apply = smsMeetingRoomPredetermineApplyMapper.selectById(applyId);
        if (isNullOrEmpty(apply)) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.MEETING_ROOM_APPLY_NOT_EXIST));
        }
        //校验会议室是否存在
        SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(meetingRoomId);
        if (isNullOrEmpty(meetingRoom)) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.MEETING_ROOM_NOT_EXIST));
        }

        //校验会议室状态
        if (!meetingRoom.getIsUse()) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.MEETING_ROOM_NOT_IS_USE));
        }
        //校验容量
        if (memberIdList.size() > meetingRoom.getCapacity()) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.MEETING_ROOM_CAPACITY_NOT_ENOUGH));
        }
        //校验会议室预定时间
        if (meetingRoom.getIsBookTime()) {
            //校验开始时间和结束时间限制
            Date startTimeLimit = meetingRoom.getStartTimeLimit();
            startTimeLimit.setYear(startDate.getYear());
            startTimeLimit.setMonth(startDate.getMonth());
            startTimeLimit.setDate(startDate.getDate());
            Date endTimeLimit = meetingRoom.getEndTimeLimit();
            endTimeLimit.setYear(endTimeLimit.getYear());
            endTimeLimit.setMonth(endTimeLimit.getMonth());
            endTimeLimit.setDate(endTimeLimit.getDate());

            if (!((startDate.compareTo(startTimeLimit) > 0 && startDate.compareTo(endTimeLimit) < 0)
                    && (endDate.compareTo(startTimeLimit) > 0 && endDate.compareTo(endTimeLimit) < 0))) {
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.EXCEEDING_THE_BOOKING_TIME_RANGE));
            }
            //校验是否超出会议室单次可预订时长上限
            long applyStartDateTime = startDate.getTime();
            long applyEndDateTime = endDate.getTime();
            int minutes = (int) ((applyEndDateTime - applyStartDateTime) / (1000 * 60));
            if (minutes > meetingRoom.getSingleTimeLimit()) {
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.EXCEEDING_THE_MAX_SINGLE_BOOKING_TIME));
            }
            //校验是否超出会议室最早可提前预定时间
            long nowTime = new Date().getTime();
            int hours = (int) ((applyStartDateTime - nowTime) / (1000 * 60 * 60));
            if (hours > meetingRoom.getEarliestBookTime()) {
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.EXCEEDING_THE_EARLIEST_BOOKING_TIME));
            }
        }

        //校验是否有申请 存在交集
        Integer count = smsMeetingRoomPredetermineApplyMapper.selectCount(new LambdaQueryWrapper<SmsMeetingRoomPredetermineApply>()
                .eq(SmsMeetingRoomPredetermineApply::getMeetingRoomId, meetingRoomId)
                .eq(SmsMeetingRoomPredetermineApply::getAllowStatus, MEETING_ALLOW_STATUS_PASS)
                .not(queryWrapper ->
                        queryWrapper.le(SmsMeetingRoomPredetermineApply::getEndTime, startDate)
                                .or()
                                .ge(SmsMeetingRoomPredetermineApply::getStartTime, endDate)));
        if (count > 0) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.CURRENT_TIME_CONFLICTS_WITH_OTHER_MEETING));
        }

        //创建预定申请表
        SmsMeetingRoomPredetermineApply predetermineApply = new SmsMeetingRoomPredetermineApply();
        predetermineApply.setId(applyId);
        predetermineApply.setUserId(userId);
        predetermineApply.setName(name);
        predetermineApply.setMeetingRoomId(meetingRoomId);
        predetermineApply.setAllowStatus(MEETING_ALLOW_STATUS_WAIT);
        predetermineApply.setStartTime(startDate);
        predetermineApply.setEndTime(endDate);
        predetermineApply.setMemberIdList(JSON.toJSONString(memberIdList));
        smsMeetingRoomPredetermineApplyMapper.updateById(predetermineApply);

        //校验是否需要审批 同时 进行通知
        if (meetingRoom.getIsAllow()) {
            List<String> AllowUserIdList = JSON.parseArray(meetingRoom.getAllowUserIdList(), String.class);
            for (String allowUserId : AllowUserIdList) {
                SmsMeetingRoomProcessDetail addDetail = new SmsMeetingRoomProcessDetail();
                addDetail.setApplyId(predetermineApply.getId());
                addDetail.setIsSign(meetingRoom.getIsSign() ? 1 : 0);
                addDetail.setIsStamp(meetingRoom.getIsStamp() ? 1 : 0);
                addDetail.setUserId(allowUserId);
                addDetail.setAllowStatus(MEETING_DETAIL_ALLOW_STATUS_WAIT);
                smsMeetingRoomProcessDetailMapper.insert(addDetail);

                //消息通知
                List<String> rangeList = new ArrayList<>();
                rangeList.add(allowUserId);
                newTipsUtil.addNewTips(TipsTypeEnum.TIPS_TYPE_ENUM_ALLOW,
                        userId,
                        RangeTypeEnum.RANGE_TYPE_ENUM_PERSON,
                        rangeList,
                        AppTypeEnum.APP_TYPE_ENUM_MEETING_ROOM,
                        predetermineApply.getId(),
                        addDetail.getId());
            }
        } else {
            predetermineApply.setAllowStatus(MEETING_ALLOW_STATUS_PASS);
            predetermineApply.setApplyEndTime(new Date());
            smsMeetingRoomPredetermineApplyMapper.updateById(predetermineApply);

            //消息通知
            newTipsUtil.allowFinishTips(predetermineApply.getId(), userId, true);
        }
    }

    /**
     * 删除会议室预约申请
     *
     * @param applyId 申请表id
     */
    public void deleteMeeting(String applyId) {
        //校验申请表是否存在
        SmsMeetingRoomPredetermineApply apply = smsMeetingRoomPredetermineApplyMapper.selectById(applyId);
        if (isNullOrEmpty(apply)) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.MEETING_ROOM_APPLY_NOT_EXIST));
        }

        SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(apply.getMeetingRoomId());
        if (meetingRoom.getIsAllow()) {
            smsMeetingRoomProcessDetailMapper.delete(new LambdaQueryWrapper<SmsMeetingRoomProcessDetail>()
                    .eq(SmsMeetingRoomProcessDetail::getApplyId, applyId));
        }

        smsMeetingRoomPredetermineApplyMapper.deleteById(applyId);
    }

    /**
     * 获取会议室地址
     *
     * @param meetingRoom 会议室
     * @return 会议室地址
     */
    public String getMeetingAddress(SmsMeetingRoomInfo meetingRoom) {
        String address = "";
        SmsOrgStructure org = smsOrgStructureMapper.selectById(meetingRoom.getOrgId());
        address += org.getOrgName();
        SmsMeetingBuilding building = smsMeetingBuildingMapper.selectById(meetingRoom.getBuildingId());
        address += building.getName();
        SmsMeetingBuildingFloor floor = smsMeetingBuildingFloorMapper.selectById(meetingRoom.getFloorId());
        address += floor.getName();
        address += meetingRoom.getName();
        return address;
    }

    /**
     * 获取会议室信息
     *
     * @param meetingRoomId 会议室id
     * @return 会议室信息
     */
    public SmsMeetingRoomInfoResp getMeetingRoomInfo(String meetingRoomId) {
        //校验会议室是否存在
        SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(meetingRoomId);
        if (isNullOrEmpty(meetingRoom)) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.MEETING_ROOM_NOT_EXIST));
        }

        SmsMeetingRoomInfoResp meetingRoomInfoResp = new SmsMeetingRoomInfoResp();
        BeanUtils.copyProperties(meetingRoom, meetingRoomInfoResp);
        SmsOrgStructure org = smsOrgStructureMapper.selectById(meetingRoom.getOrgId());
        meetingRoomInfoResp.setOrgName(org.getOrgName());
        SmsMeetingBuilding building = smsMeetingBuildingMapper.selectById(meetingRoom.getBuildingId());
        meetingRoomInfoResp.setBuildingName(building.getName());
        SmsMeetingBuildingFloor floor = smsMeetingBuildingFloorMapper.selectById(meetingRoom.getFloorId());
        meetingRoomInfoResp.setFloorName(floor.getName());
        if (!isNullOrEmpty(meetingRoom.getDeviceList())) {
            meetingRoomInfoResp.setDeviceList(JSON.parseArray(meetingRoom.getDeviceList(), String.class));
        }
        if (!isNullOrEmpty(meetingRoom.getAllowUserIdList())) {
            meetingRoomInfoResp.setAllowUserIdList(JSON.parseArray(meetingRoom.getAllowUserIdList(), String.class));
        }
        if (!isNullOrEmpty(meetingRoom.getStartTimeLimit())) {
            meetingRoomInfoResp.setStartTimeLimit(TimeUtil.TimeFormatSting(meetingRoom.getStartTimeLimit()));
        }
        if (!isNullOrEmpty(meetingRoom.getEndTimeLimit())) {
            meetingRoomInfoResp.setEndTimeLimit(TimeUtil.TimeFormatSting(meetingRoom.getEndTimeLimit()));
        }

        return meetingRoomInfoResp;
    }

}
